package site.potatoblog.threadpool.manager.core;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.annotation.EnableAsync;
import site.potatoblog.threadpool.manager.builder.impl.ThreadPoolDetailInfoBuilder;
import site.potatoblog.threadpool.manager.vo.ThreadPoolArgs;
import site.potatoblog.threadpool.manager.vo.ThreadPoolDetailInfo;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


@EnableAsync
public class DynamicThreadPoolManager implements ApplicationRunner, ApplicationContextAware {
    private static final Logger LOGGER= LoggerFactory.getLogger(DynamicThreadPoolManager.class);
    private static ConcurrentHashMap<String,DynamicThreadPool> threadPools;
    private ApplicationContext context;


    @Override
    public void run(ApplicationArguments args) {
       Map<String,DynamicThreadPool> threadPoolBeans=context.getBeansOfType(DynamicThreadPool.class);
       int size=threadPoolBeans.size();
       if(size==0){
           return;
       }
       int expectSize= (int) (size/0.75f+1.0f);
       threadPools=new ConcurrentHashMap<>(expectSize);
       threadPools.putAll(threadPoolBeans);
    }


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context=applicationContext;
    }

    public List<ThreadPoolArgs> getAllThreadPoolArgs(){
        List<ThreadPoolArgs> poolInfos=new ArrayList<>();
        for (Map.Entry<String, DynamicThreadPool> entry : threadPools.entrySet()) {
            DynamicThreadPool threadPool=entry.getValue();
            ThreadPoolArgs threadPoolInfo=mergeArgs(threadPool);
            poolInfos.add(threadPoolInfo);
        }
        return poolInfos;
    }
    public ThreadPoolDetailInfo getThreadPoolDetailByName(String name){
        DynamicThreadPool threadPool=threadPools.get(name);
        return mergeDetails(threadPool);
    }

    public boolean updateThreadPool(ThreadPoolArgs threadPoolArgs){
        try{
            DynamicThreadPool threadPool=threadPools.get(threadPoolArgs.getThreadPoolName());
            threadPool.setAppName(threadPoolArgs.getAppName());
            threadPool.setCorePoolSize(threadPoolArgs.getCorePoolSize());
            threadPool.setMaxPoolSize(threadPoolArgs.getMaxPoolSize());
            threadPool.setQueueCapacity(threadPoolArgs.getQueueCapacity());
            threadPool.setKeepAliveSeconds(threadPoolArgs.getKeepAliveSeconds());
            threadPool.setActiveThreshold(threadPoolArgs.getActiveThreshold());
            threadPool.setCapacityThreshold(threadPoolArgs.getCapacityThreshold());
        }catch (Exception e){
            return false;
        }
        return true;
    }

    private ThreadPoolDetailInfo mergeDetails(DynamicThreadPool threadPool){
        return ThreadPoolDetailInfoBuilder.create()
                .setAppName(threadPool.getAppName())
                .setThreadPoolName(threadPool.getThreadPoolName())
                .setCorePoolSize(threadPool.getCorePoolSize())
                .setMaxPoolSize(threadPool.getMaxPoolSize())
                .setQueueCapacity(threadPool.getQueueCapacity())
                .setKeepAliveSeconds(threadPool.getKeepAliveSeconds())
                .setQueueRemainingCapacity(threadPool.getQueue().remainingCapacity())
                .setActiveCount(threadPool.getActiveCount())
                .setAllowCoreThreadTimeOut(threadPool.allowsCoreThreadTimeOut())
                .setCompletedTaskCount(threadPool.getCompletedTaskCount())
                .setLargestPoolSize(threadPool.getLargestPoolSize())
                .setQueueType(threadPool.getQueue().getClass().getSimpleName())
                .setTaskCount(threadPool.getTaskCount())
                .setQueueSize(threadPool.getQueue().size())
                .setPoolSize(threadPool.getPoolSize())
                .setRejectCount(threadPool.getRejectCount())
                .setCurrentTime(new Date(System.currentTimeMillis()))
                .setThreadFactoryType(threadPool.getThreadFactory().getClass().getSimpleName())
                .setRejectHandlerType(threadPool.getRejectedExecutionHandler().getClass().getSimpleName())
                .build();
    }
    private ThreadPoolArgs mergeArgs(DynamicThreadPool threadPool){
        return new ThreadPoolArgs(threadPool.getCorePoolSize(),threadPool.getMaxPoolSize(),threadPool.getKeepAliveSeconds(),threadPool.getQueueCapacity(),threadPool.getCapacityThreshold(),threadPool.getActiveThreshold(),threadPool.getQueue().getClass().getSimpleName(),threadPool.getAppName(),threadPool.getThreadPoolName(),threadPool.getThreadFactory().getClass().getSimpleName(),threadPool.getRejectedExecutionHandler().getClass().getSimpleName());
    }
}
